package com.hbean.system.aspect;

import com.hbean.entity.SysLog;
import com.hbean.entity.SysUser;
import com.hbean.service.SysLogService;
import com.hbean.system.annotation.LogMethod;
import com.hbean.system.config.SysCache;
import com.hbean.system.listener.SessionListener;
import com.hbean.system.websocket.WebSocketServer;
import com.hbean.utils.HUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: null
 * @Project: hbean
 * @Author: hjibo
 * @CreateDate: 2018/11/2 10:27
 * @ModificationHistory: （who whatTime doWhat）
 */

@Slf4j
@Aspect
@Component
public class LogAspect {

    @Autowired
    private SysLogService sysLogService;
    @Autowired
    private SysCache sysCache;
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 切点
     */
    @Pointcut("@annotation(com.hbean.system.annotation.LogMethod)")
    public void pointcutMethod() {
    }

    /**
     * 切面
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("pointcutMethod()")
    public Object around(ProceedingJoinPoint point) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();

        String methodName = point.getSignature().getName();//方法名
        String className = point.getTarget().getClass().getName();//类的全限定名
        Method[] methods = Class.forName(className).getMethods();//类的所有方法对象

        List<Method> methodList = Arrays.stream(methods).filter(method -> method.getName().equals(methodName)).collect(Collectors.toList());
        Object object = null;
        for(Method method:methodList){
            switch (method.getAnnotation(LogMethod.class).logType()){
                case 0:
                    object = point.proceed();//执行目标方法
                    int code0 = (int) ((Map)object).get("code");
                    //记录操作日志
                    SysLog sysLog0 = new SysLog();
                    sysLog0.setSl00(HUtil.uuidOf18());
                    sysLog0.setSl01("201811031703100261");//日志类型 操作
                    sysLog0.setSl02((String) session.getAttribute("userId"));//操作人人
                    sysLog0.setSl03(HUtil.dateToString(new Date(),"yyyyMMddHHmmss"));//操作时间
                    sysLog0.setSl04(method.getAnnotation(LogMethod.class).logName());//操作名称
                    sysLog0.setSl05(code0 == 0 ? "成功" : "失败");//操作结果
                    this.sysLogService.insertData(sysLog0);
                    break;
                case 1:
                    switch (method.getAnnotation(LogMethod.class).logName()){
                        /**
                         * 登陆方法 切点
                         */
                        case "loginIn":
                            try {
                                object = point.proceed();//执行目标方法
                                int code = (int) ((Map)object).get("code");
                                SysUser sysUser = (SysUser)((Map)object).get("data");
                                switch (code){
                                    case 0:
                                        //判断用户是否已经登录，如果登录则清除用户信息,实现用户的单点登录
                                        if(SessionListener.sessionMap.get(sysUser.getSu00()) != null){
                                            SessionListener.sessionMap.get(sysUser.getSu00()).removeAttribute("userId");

                                            //消息推送
                                            Map dataMap = new HashMap();
                                            dataMap.put("loginAtOtherPlace", "账号已在其他地方登录！");
                                            webSocketServer.sendMessage(HUtil.mapToJsonStr(dataMap),sysUser.getSu00());
                                        }

                                        //将当前登录用户的id信息存入session中；同时将此session以用户id为key存入内存中
                                        session.setAttribute("userId",sysUser.getSu00());
                                        SessionListener.sessionMap.put(sysUser.getSu00(),session);

                                        //将上线信息推送给在线所有用户
                                        Map dataMap = new HashMap();
                                        dataMap.put("loginOnInfo",sysUser.getSu01()+" 上线了！");
                                        webSocketServer.sendMessageToAll(HUtil.mapToJsonStr(dataMap));

                                        //记录登录日志
                                        SysLog sysLog = new SysLog();
                                        sysLog.setSl00(HUtil.uuidOf18());//主键
                                        sysLog.setSl01("201810282236115607");//日志类型 登陆
                                        sysLog.setSl02(sysUser.getSu00());//登录人
                                        sysLog.setSl03(HUtil.dateToString(new Date(),"yyyyMMddHHmmss"));//登录时间
                                        sysLog.setSl04(HUtil.ipNetAddressOfRemote(request));//登录IP
                                        sysLog.setSl05(HUtil.ipNetAddressOfLocal(request));//服务器IP
                                        this.sysLogService.insertData(sysLog);
                                        break;
                                    default:
                                        break;
                                }
                            } catch (Throwable throwable) {
                                throwable.printStackTrace();
                            }
                            break;
                        /**
                         * 退出方法 切点
                         */
                        case "loginOff":
                            //如果session中用户id不为空，则清除用户id
                            if(session.getAttribute("userId") != null){

                                //消息推送
                                Map dataMap = new HashMap();
                                dataMap.put("loginOffInfo", sysCache.getSysUserByID((String) session.getAttribute("userId")).getSu01()+" 下线了（退出）！");
                                webSocketServer.sendMessageToAll(HUtil.mapToJsonStr(dataMap));

                                SessionListener.sessionMap.remove((String) session.getAttribute("userId"));
                                session.removeAttribute("userId");
                            }
                            object = point.proceed();//执行目标方法
                            break;
                        default:
                            break;
                    }
                    break;
                    default:
                        break;
            }

        }
        return object;
    }

}
